package com.jacars.biz.user.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jacars.biz.user.dao.model.JsptRoleUser;
import com.jacars.biz.user.dao.model.JsptUserExcel;
import com.jacars.biz.user.dao.service.JsptRoleUserService;
import com.jacars.biz.user.dao.service.JsptUserService;
import com.jacars.biz.user.dto.GrantUserRoles;
import com.jacars.biz.user.service.UserService;
import com.jacars.common.annotation.LoginUser;
import com.jacars.common.api.PageResult;
import com.jacars.common.api.Result;
import com.jacars.common.constant.CommonConstant;
import com.jacars.common.model.JsptRole;
import com.jacars.common.model.JsptUser;
import com.jacars.common.model.LoginAppUser;
import com.jacars.common.model.UserType;
import com.jacars.common.utils.ExcelUtil;
import com.jacars.common.utils.FuncUtil;
import com.jacars.db.support.Query;
import com.jacars.log.annotation.AuditLog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

//import com.jacars.search.client.service.IQueryService;
//import com.jacars.search.model.LogicDelDto;
//import com.jacars.search.model.SearchDto;

//import AuditLog;

/**
 * @author 作者 owen E-mail: 624191343@qq.com
 * 用户
 */
@Slf4j
@RestController
@Api(tags = "用户模块api")
public class UserController {
    private static final String ADMIN_CHANGE_MSG = "超级管理员不给予修改";
    /**
     * 全文搜索逻辑删除Dto
     */
//    private static final LogicDelDto SEARCH_LOGIC_DEL_DTO = new LogicDelDto("isDel", "否");

    @Autowired
    private UserService userService;

    @Autowired
    private JsptUserService jsptUserService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JsptRoleUserService jsptRoleUserService;

    /**
     * 当前登录用户 LoginAppUser
     *
     * @return
     */
    @ApiOperation(value = "根据access_token当前登录用户")
    @GetMapping("/users/current")
    public Result<LoginAppUser> getLoginAppUser(@LoginUser(isFull = true) JsptUser user) {
        return Result.succeed(userService.getLoginAppUser(user));
    }

    /**
     * 查询用户实体对象JsptUser
     */
    @GetMapping(value = "/users/name/{username}")
    @ApiOperation(value = "根据用户名查询用户实体")
    @Cacheable(value = "user", key = "#username")
    public Result<JsptUser> selectByUsername(@PathVariable String username) {
        return Result.succeed(userService.selectByUsername(username));
    }

    /**
     * 查询用户登录对象LoginAppUser
     */
    @GetMapping(value = "/users-anon/login", params = "username")
    @ApiOperation(value = "根据用户名查询用户")
    public LoginAppUser findByUsername(String username) {
        LoginAppUser loginAppUser = userService.findByUsername(username);
        return loginAppUser;
    }

    /**
     * 根据userId查询用户信息
     *
     * @param userId userId
     */
    @GetMapping(value = "/users/userId/{userId}")
    @ApiOperation(value = "根据UserId查询用户")
    public Result<JsptUser> findByUserId(@PathVariable("userId") String userId) {
        return Result.succeed(userService.findByUserId(userId));
    }


    /**
     * 通过手机号查询用户、角色信息
     *
     * @param mobile 手机号
     */
    @GetMapping(value = "/users-anon/mobile", params = "mobile")
    @ApiOperation(value = "根据手机号查询用户")
    public JsptUser findByMobile(String mobile) {
        return userService.findByMobile(mobile);
    }

    /**
     * 根据OpenId查询用户信息
     *
     * @param openId openId
     */
    @GetMapping(value = "/users-anon/openId", params = "openId")
    @ApiOperation(value = "根据OpenId查询用户")
    public JsptUser findByOpenId(String openId) {
        return userService.findByOpenId(openId);
    }

    @GetMapping("/users/{id}")
    public JsptUser findUserById(@PathVariable Long id) {
        return userService.findUserById(id);
    }

    /**
     * 管理后台修改用户
     *
     * @param jsptUser
     */
    @PutMapping("/users")
    @CachePut(value = "user", key = "#jsptUser.username", unless = "#result == null")
    //@AuditLog(operation = "'更新用户:' + #sysUser")
    public void updateSysUser(@RequestBody JsptUser jsptUser) {
        userService.updateSysUser(jsptUser);
    }

    /**
     * 管理后台给用户分配角色
     *
     * @param id
     * @param grantUserRoles
     */
    @PostMapping("/users/grantUserRoles")
    public Result grantUserRoles(@RequestParam("userId") Long id, @RequestBody GrantUserRoles grantUserRoles) {
        userService.setRoleToUser(id, grantUserRoles.getRoleIds());
        return Result.succeed();
    }


    /**
     * 获取用户的角色
     *
     * @param
     * @return
     */
    @GetMapping("/users/{id}/roles")
    public List<JsptRole> findRolesByUserId(@PathVariable Long id) {
        return userService.findRolesByUserId(id);
    }


    /**
     * 用户查询列表
     *
     * @param params
     * @return
     */
    @ApiOperation(value = "用户查询列表")
    @GetMapping("/users/userPage")
    public PageResult<JsptUser> userPage(@RequestParam Map<String, Object> params, Query query) {
        //todo whf 这里是通过点击部门，该部门用户列表的接口。
        //在实际使用中，发现只查询了本级，需要添加一个配置项，可以本级查询和带下级查询的
        return userService.findUsers(params, query);
    }

    /**
     * 修改用户状态
     *
     * @param params
     * @return
     */
    @ApiOperation(value = "修改用户状态")
    @GetMapping("/users/updateEnabled")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户id", required = true, dataType = "Integer"),
            @ApiImplicitParam(name = "enabled", value = "是否启用", required = true, dataType = "Boolean")
    })
    public Result updateEnabled(@RequestParam Map<String, Object> params) {
        Long id = MapUtils.getLong(params, "id");
        if (checkAdmin(id)) {
            return Result.failed(ADMIN_CHANGE_MSG);
        }
        return userService.updateEnabled(params);
    }

    /**
     * 管理后台，给用户重置密码
     *
     * @param id
     */
    @PutMapping(value = "/users/{id}/password")
    //@AuditLog(operation = "'重置用户密码:' + #id")
    public Result resetPassword(@PathVariable Long id) {
        if (checkAdmin(id)) {
            return Result.failed(ADMIN_CHANGE_MSG);
        }
        userService.updatePassword(id, null, null);
        return Result.succeed("重置成功");
    }

    /**
     * 模糊查询用户，根据用户名左右匹配
     *
     * @param userName
     */
    @GetMapping(value = "/users/fuzzy")
    public PageResult<JsptUser> fuzz(@RequestParam(name = "userName", required = false) String userName) {
        List<JsptUser> list = null;
        if (FuncUtil.equals("", userName) || FuncUtil.isNull(userName)) {
            // 查询全部
            list = jsptUserService.list();
        } else {
            // 模糊查询
            list = jsptUserService.list(Wrappers.<JsptUser>lambdaQuery().like(JsptUser::getRealName, userName));

        }

        return PageResult.succeed(list);
    }

    /**
     * 用户自己修改密码
     */
    @PostMapping(value = "/users/password")
    public Result resetPassword(@RequestBody JsptUser jsptUser, @LoginUser JsptUser jsptUser1) {
        jsptUser.setId(jsptUser1.getId());
        if (checkAdmin(jsptUser.getId())) {
            return Result.failed(ADMIN_CHANGE_MSG);
        }

        userService.updatePassword(jsptUser.getId(), jsptUser.getOldPassword(), jsptUser.getNewPassword());
        return Result.succeed("重置成功");
    }

    /**
     * 删除用户
     *
     * @param ids
     */
    @PostMapping(value = "/users/remove/{ids}")
    @AuditLog(operation = "'删除用户:' + #id")
    public Result delete(@PathVariable List<Long> ids) {
        for (Long id : ids) {
            if (checkAdmin(id)) {
                return Result.failed(ADMIN_CHANGE_MSG);
            }
        }

        // 删除用户对应的角色
        jsptRoleUserService.remove(Wrappers.<JsptRoleUser>lambdaQuery().in(JsptRoleUser::getUserId, ids));

        // 删除用户
        jsptUserService.removeByIds(ids);

        return Result.succeed("删除成功");
    }


    /**
     * 新增or更新
     *
     * @param jsptUser
     * @return
     */
    @CacheEvict(value = "user", key = "#jsptUser.username")
    @PostMapping("/users/create")
    @AuditLog(operation = "'新增或更新用户:' + #jsptUser.username")
    public Result create(@RequestBody JsptUser jsptUser) {
        // 使用前端传递过来的tenantId，不用操作人的tenantId
        jsptUser.setTenantId(null);
        jsptUser.setPassword(passwordEncoder.encode(jsptUser.getPassword()));
        boolean result = jsptUserService.save(jsptUser);

        //设置角色
        if (result && StrUtil.isNotEmpty(jsptUser.getRoleId())) {
            jsptRoleUserService.remove(Wrappers.<JsptRoleUser>lambdaQuery().eq(JsptRoleUser::getUserId, jsptUser.getId()));
            List roleIds = Arrays.asList(jsptUser.getRoleId().split(","));
            if (!CollectionUtils.isEmpty(roleIds)) {
                List<JsptRoleUser> roleUsers = new ArrayList<>(roleIds.size());
                roleIds.forEach(roleId -> roleUsers.add(new JsptRoleUser(jsptUser.getId(), Long.parseLong(roleId.toString()))));
                // roleUserService.saveBatch(roleUsers);
                jsptRoleUserService.saveBatch(roleUsers);
            }
        }

        return Result.succeed();
    }

    /**
     * 新增or更新
     *
     * @param jsptUser
     * @return
     */
    @CacheEvict(value = "user", key = "#jsptUser.username")
    @PostMapping("/users/update")
    @AuditLog(operation = "'新增或更新用户:' + #jsptUser.username")
    public Result update(@RequestBody JsptUser jsptUser) throws Exception {
        return userService.saveOrUpdateUser(jsptUser);
    }

    /**
     * 导出excel
     *
     * @return
     */
    @PostMapping("/users/export")
    public void exportUser(@RequestParam Map<String, Object> params, HttpServletResponse response) throws IOException {
        List<JsptUserExcel> result = userService.findAllUsers(params);
        //导出操作
        ExcelUtil.exportExcel(result, null, "用户", JsptUserExcel.class, "user", response);
    }
    /**
     * 导入excel
     *
     * @return Result
     */
    @PostMapping(value = "/users/import")
    public Result importExcl(@RequestParam("file") MultipartFile excl) throws Exception {
        int rowNum = 0;
        if (!excl.isEmpty()) {
            List<JsptUserExcel> list = ExcelUtil.importExcel(excl, 0, 1, JsptUserExcel.class);
            rowNum = list.size();
            if (rowNum > 0) {
                List<JsptUser> users = new ArrayList<>(rowNum);
                list.forEach(u -> {
                    JsptUser user = new JsptUser();
                    BeanUtil.copyProperties(u, user);
                    user.setPassword(CommonConstant.DEF_USER_PASSWORD);
                    user.setTenantId(UserType.BACKEND.name());
                    users.add(user);
                });
                userService.saveBatch(users);
            }
        }
        return Result.succeed("导入数据成功，一共【" + rowNum + "】行");
    }

    /**
     * 是否超级管理员
     */
    private boolean checkAdmin(long id) {
        return FuncUtil.equals(id, 1L);
    }
}
